﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using WindowsGame1;
using System.Collections.Generic;

public class Player
{
    public Vector2 RelPosition;                    // Position relative to collection.
    public int Budget;                      // Max number of alive particles.
    float NextSpawnIn;                      // This is a random number generated using the SecPerSpawn.
    float SecPassed;                        // Time pased since last spawn.

    public Vector2 SecPerSpawn;
    public Vector2 SpawnDirection;
    public Vector2 SpawnNoiseAngle;
    public Vector2 StartLife;
    public Vector2 StartScale;
    public Vector2 EndScale;
    public Color StartColor1;
    public Color StartColor2;
    public Color EndColor1;
    public Color EndColor2;
    public Vector2 StartSpeed;
    public Vector2 EndSpeed;

    public Vector2 Position;
    public Vector2 Size = new Vector2(0.0233f, 0.1667f);
    SpriteBatch spriteBatch;
    public Texture2D particleBase;
    public Texture2D liveBase;
    float Speed = 1.667f;
    float difficulty = 3;
    public float aspect = 1.5f;

    public List<Live> livesSprites;

    public float Aspect
    {
        get { return aspect; }
        set
        {
            if (aspect != value)
            {
                //Position.X /= aspect / value;
                //if (this.Number == 1)
                //{
                //    for (int i = 0; i < 15; i++)
                //    {
                //        particleSystemLives.EmitterList[i].RelPosition.X /= aspect / value;
                //    }
                //}
                aspect = value;
            }
        }
    }
    int Scale;
    public string Name;
    int Number;
    public int Lives;
    public ParticleSystem particleSystem;
    public ParticleSystem particleSystemLives;
    public bool isCPU = false;
    float targetY;
    float rndOffset;
    Random random;
    public float TargetY
    {
        get
        {
            return targetY+rndOffset;
        }
        set
        {
            if (Math.Round(value, 3) != Math.Round(targetY, 3))
            {
                rndOffset = (float)((random.NextDouble() - 0.5f) * Size.Y);
                targetY = value;
            }
        }
    }

    public void setDifficulty(float diff)
    {
        this.difficulty = diff;
    }

    public Player(int nr, Vector2 windowSize, SpriteBatch spriteBatch, Texture2D particleBase, Texture2D liveBaseTex)
    {
        //Size = new Vector2();
        this.random = new Random();
        this.Scale = (int)windowSize.Y;
        this.Name = "Player " + nr;
        this.spriteBatch = spriteBatch;
        this.Number = nr;
        //this.particleSystem = new ParticleSystem(Position);
        //this.particleSystemLives = new ParticleSystem(Vector2.Zero);
        this.particleBase = particleBase;
        this.liveBase = liveBaseTex;
        livesSprites = new List<Live>();
    }

    public void ReduceLife()
    {
        Lives--;
        livesSprites[Lives].visible = false;
        //particleSystemLives.EmitterList[Lives].Budget = 0;
    }

    public void Reset(int lives)
    {
        for (int i = 0; i < lives; i++)
        {
            livesSprites[i].visible = true;
            //particleSystemLives.EmitterList[i].Budget = 50;
        }
        for (int i = lives; i < 15; i++)
        {
            livesSprites[i].visible = false;
            //particleSystemLives.EmitterList[i].Budget = 0;
        }
        this.Lives = lives;
    }

    public void Init()
    {
        switch (this.Number)
        {
            case 0:
                Position = new Vector2(this.Size.X/2, 0.5f);
                Size.Y *= 1;

                this.SecPerSpawn = new Vector2(0.0005f, 0.0007f);
                this.SpawnDirection = new Vector2(0, -1);
                this.SpawnNoiseAngle = new Vector2((float)(-0.128f * Math.PI * 8), (float)(0.128f * Math.PI * 8));
                this.StartLife = new Vector2(0.3f, 0.5f);
                this.StartScale = new Vector2(0.025f, 0.0375f);
                this.EndScale = new Vector2(0.0125f, 0.0180f);
                this.StartColor1 = Color.Crimson;
                this.StartColor2 = Color.Green;
                this.EndColor1 = Color.Orange;
                this.EndColor2 = Color.Orange;
                this.StartSpeed = new Vector2(0.12f, 0.16f);
                this.EndSpeed = new Vector2(0.06f, 0.08f);
                this.NextSpawnIn = MathLib.LinearInterpolate(SecPerSpawn.X, SecPerSpawn.Y, random.NextDouble());
                this.SecPassed = 0.0f;
                //particleSystem.AddEmitter(new Vector2(0.0005f, 0.0007f),
                //                    new Vector2(0, -1),
                //                    new Vector2((float)(-0.128f * Math.PI * 8), (float)(0.128f * Math.PI * 8)),
                //                    new Vector2(0.3f, 0.5f),
                //                    new Vector2(0.025f, 0.0375f),
                //                    new Vector2(0.0125f, 0.0180f),
                //                    Color.Crimson, Color.Orange, Color.Orange, Color.Orange,
                //                    new Vector2(0.12f, 0.16f),
                //                    new Vector2(0.06f, 0.08f),
                //                    2000, Vector2.Zero, particleBase);

                for (int i = 0; i < 15; i++)
                {
                    //particleSystemLives.AddEmitter(new Vector2(0.01f, 0.015f),
                    //                new Vector2(0, -1),
                    //                new Vector2((float)(-0.128f * Math.PI * 8), (float)(0.128f * Math.PI * 8)),
                    //                new Vector2(0.3f, 0.5f),
                    //                new Vector2(0.025f, 0.0375f),
                    //                new Vector2(0.0125f, 0.0180f),
                    //                Color.Crimson, Color.Orange, Color.Orange, Color.Orange,
                    //                new Vector2(0.06f, 0.08f),
                    //                new Vector2(0.03f, 0.04f),
                    //                50, new Vector2((0.09f + 0.025f * i) * Aspect, 0.1f), particleBase);

                    livesSprites.Add(new Live() { particleBase = liveBase, Position = new Vector2((0.09f + 0.03f * i) * Aspect, 0.1f), spriteBatch = spriteBatch});
                }
                break;
            case 1:
                Position = new Vector2(1.0f * Aspect - this.Size.X/2, 0.5f - this.Size.Y / 2);

                this.SecPerSpawn = new Vector2(0.0005f, 0.0007f);
                this.SpawnDirection = new Vector2(0, -1);
                this.SpawnNoiseAngle = new Vector2((float)(-0.128f * Math.PI * 8), (float)(0.128f * Math.PI * 8));
                this.StartLife = new Vector2(0.3f, 0.5f);
                this.StartScale = new Vector2(0.025f, 0.0375f);
                this.EndScale = new Vector2(0.0125f, 0.0180f);
                this.StartColor1 = Color.DarkBlue;
                this.StartColor2 = Color.RoyalBlue;
                this.EndColor1 = Color.RoyalBlue;
                this.EndColor2 = Color.RoyalBlue;
                this.StartSpeed = new Vector2(0.12f, 0.16f);
                this.EndSpeed = new Vector2(0.06f, 0.08f);
                this.NextSpawnIn = MathLib.LinearInterpolate(SecPerSpawn.X, SecPerSpawn.Y, random.NextDouble());
                this.SecPassed = 0.0f;
                //particleSystem.AddEmitter(new Vector2(0.0005f, 0.00075f),
                //                    new Vector2(0, -1),
                //                    new Vector2((float)(-0.128f * Math.PI * 8), (float)(0.128f * Math.PI * 8)),
                //                    new Vector2(0.3f, 0.5f),
                //                    new Vector2(0.025f, 0.0375f),
                //                    new Vector2(0.0125f, 0.0180f),
                //                    Color.DarkBlue, Color.RoyalBlue, Color.RoyalBlue, Color.RoyalBlue,
                //                    new Vector2(0.12f, 0.16f),
                //                    new Vector2(0.06f, 0.08f),
                //                    2000, Vector2.Zero, particleBase);

                for (int i = 0; i < 15; i++)
                {
                //    particleSystemLives.AddEmitter(new Vector2(0.01f, 0.015f),
                //                    new Vector2(0, -1),
                //                    new Vector2((float)(-0.128f * Math.PI * 8), (float)(0.128f * Math.PI * 8)),
                //                    new Vector2(0.3f, 0.5f),
                //                    new Vector2(0.025f, 0.0375f),
                //                    new Vector2(0.0125f, 0.0180f),
                //                    Color.DarkBlue, Color.RoyalBlue, Color.RoyalBlue, Color.RoyalBlue,
                //                    new Vector2(0.06f, 0.08f),
                //                    new Vector2(0.03f, 0.04f),
                //                    50, new Vector2((0.91f - 0.025f * i) * Aspect, 0.9f), particleBase);
                //}
                    livesSprites.Add(new Live() { particleBase = liveBase, Position = new Vector2((0.91f - 0.03f * i) * Aspect, 0.9f), spriteBatch = spriteBatch });
                }
                break;
            default:
                Position = new Vector2(0, 0.5f);
                break;
        }
    }

    public void Up(GameTime gameTime)
    {
        if (!isCPU)
        {
            if (this.Position.Y > 0)
            {
                this.Position.Y -= this.Speed * ((float)gameTime.ElapsedGameTime.Milliseconds / 1000);
            }
            if (this.Position.Y - 0.1 < 0)
            {
                this.Position.Y = 0.05f;
            }
        }
    }
    public void Down(GameTime gameTime)
    {
        if (!isCPU)
        {
            if ((this.Position.Y + this.Size.Y) < 1.0f)
            {
                this.Position.Y += this.Speed * ((float)gameTime.ElapsedGameTime.Milliseconds / 1000);
            }
            if (this.Position.Y > 1.0f - this.Size.Y)
            {
                this.Position.Y = 1.0f - this.Size.Y;
            }
        }
    }

    void AIMove(float dt)
    {
        if (isCPU)
        {
            if (Math.Abs((Position.Y + Size.Y / 2) - targetY) < (Speed / 3) * dt) 
            {
                Position.Y = targetY - Size.Y / 2;
            }
            else
            {
                if (Position.Y + Size.Y / 2 > targetY)
                {
                    Position.Y -= Speed * dt/(difficulty);
                    if (Position.Y < 0)
                    {
                        Position.Y = 0;
                    }
                }
                else
                {
                    Position.Y += Speed * dt/(difficulty);
                    if (Position.Y+Size.Y > 1)
                    {
                        Position.Y = 1-Size.Y;
                    }
                }
            }
        }
    }

    public void Update(float dt, Vector2 ballPos, Vector2 ballDir)
    {
        Vector2 StartDirection = Vector2.Transform(SpawnDirection, Matrix.CreateRotationZ(MathLib.LinearInterpolate(SpawnNoiseAngle.X, SpawnNoiseAngle.Y, random.NextDouble())));
        StartDirection.Normalize();
        Vector2 EndDirection = StartDirection * MathLib.LinearInterpolate(EndSpeed.X, EndSpeed.Y, random.NextDouble());
        StartDirection *= MathLib.LinearInterpolate(StartSpeed.X, StartSpeed.Y, random.NextDouble());
        //particleSystem.Update(dt);
        //particleSystemLives.Update(dt);
        //particleSystem.Position = Position;
        //particleSystem.Position = new Vector2(0, Size.Y)+Position;
        if (isCPU)
        {
            CalculateBallLanding(ballPos, ballDir, dt);
            AIMove(dt);
        }
    }

    void CalculateBallLanding(Vector2 ballPos, Vector2 ballDir, float dt)
    {
        // This method is going to calculate where the ball is going to "land" if it doesn't change its direction.
        // If ball is moving left (away from the CPU)
        if (ballDir.X < 0)
        {
            float wallX = Size.X * 1.5f;
            float distY;
            float distX = ballPos.X - wallX;
            float tempTargetY;
            if (ballDir.Y > 0)
            {
                distY = 1.0f - ballPos.Y;
            }
            else
            {
                distY = ballPos.Y;
            }
            if (Math.Abs(distX / ballDir.X) < Math.Abs(distY / ballDir.Y))
            {
                // Direct hit without bounce.
                tempTargetY = Math.Abs(distX) / Math.Abs(ballDir.X) * Math.Abs(ballDir.Y) + ballPos.Y;
            }
            else
            {
                float rawY = Math.Abs(distX) / Math.Abs(ballDir.X) * Math.Abs(ballDir.Y) - distY;
                float afterpoint = rawY - (float)Math.Floor(rawY);
                int beforePoint = (int)rawY;
                if (beforePoint > 0)
                {
                    beforePoint *= 1;
                }
                if (beforePoint % 2 == 0)
                {
                    // it's even
                    if (ballDir.Y > 0)
                    {
                        tempTargetY = 1.0f - afterpoint;
                    }
                    else
                    {
                        tempTargetY = afterpoint;
                    }
                }
                else
                {
                    // it's odd
                    if (ballDir.Y < 0)
                    {
                        tempTargetY = 1.0f - afterpoint;
                    }
                    else
                    {
                        tempTargetY = afterpoint;
                    }
                }
            }
            ballPos = new Vector2(wallX, tempTargetY);
            ballDir.X *= -1;
            ballDir *= 1.10f;
        }
        // Didn't set an else if by purpose so that when the first if has been handled, the calculation continues after it has hit the opponents platform.
        if (ballDir.X > 0)
        {
            float wallX = Aspect-Size.X * 1.5f;
            float distY;
            float distX = wallX - ballPos.X;
            if (ballDir.Y > 0)
            {
                distY = 1.0f - ballPos.Y;
            }
            else
            {
                distY = ballPos.Y;
            }
            if (Math.Abs(distX / ballDir.X) < Math.Abs(distY / ballDir.Y))
            {
                // Direct hit without bounce.
                TargetY = distX / ballDir.X * ballDir.Y + ballPos.Y;
            }
            else
            {
                float rawY = Math.Abs(distX / ballDir.X * Math.Abs(ballDir.Y))-distY;
                float afterpoint = rawY - (float)Math.Floor(rawY);
                int beforePoint = (int)rawY;
                if (beforePoint % 2 == 0)
                {
                    // it's even
                    if (ballDir.Y > 0)
                    {
                        TargetY = 1.0f - afterpoint;
                    }
                    else
                    {
                        TargetY = afterpoint;
                    }
                }
                else
                {
                    // it's odd
                    if (ballDir.Y < 0)
                    {
                        TargetY = 1.0f - afterpoint;
                    }
                    else
                    {
                        TargetY = afterpoint;
                    }
                }
            }
        }
    }

    public void SetScale(int Scale)
    {
        this.Scale = Scale;
    }

    public void Render(Vector2 Offset)
    {
        float currScale = 0.1f;
        //spriteBatch.Draw(particleBase, new Rectangle((int)((Position.X - 0.5f * currScale) * Scale + Offset.X), (int)((Position.Y - 0.5f * currScale) * Scale + Offset.Y), (int)(currScale * Scale), (int)(currScale * Scale)), null, StartColor2, 0, Vector2.Zero, SpriteEffects.None, 0);
        spriteBatch.Draw(particleBase, new Rectangle((int)((Position.X - 0.5f * currScale) * Scale + Offset.X+ 16), (int)((Position.Y - 0.5f * currScale) * Scale + Offset.Y),(int)( particleBase.Width * currScale), (int)(currScale * particleBase.Height * 2)), null, StartColor2, 0, Vector2.Zero, SpriteEffects.None, 0);
        //particleSystem.Draw(spriteBatch, Scale, Offset);
        //particleSystemLives.Draw(spriteBatch, Scale, Offset);

        foreach (Live l in livesSprites)
        {
            if (l.visible)
                l.spriteBatch.Draw(l.particleBase, new Rectangle((int)((l.Position.X - 0.5f * currScale) * Scale + Offset.X + 16), (int)((l.Position.Y - 0.5f * currScale) * Scale + Offset.Y), (int)l.particleBase.Width / 4, l.particleBase.Height / 4), StartColor2);
        }
    }
}